#include "MeshLoader.h"


MeshLoader::MeshLoader(ResourceManager* rm)
	:Component(COMP_MESH_LOADER),
	m_resourceManager(rm)
{
}


MeshLoader::~MeshLoader(void)
{
}

void MeshLoader::AddedToObject()
{
	RequestMessage(MSG_LOAD_MESH,&MeshLoader::Load);
}

void MeshLoader::Load(const Message& msg)
{
	string name;
	AuxUnGroupArgus(msg.p,name);
	Load(name);
}


/*
Load the mesh in DataStream.
send a global message to other component.
Add this model to ResourceManager
*/
void MeshLoader::Load(string path)
{
	try
	{
	if(path=="")
		EXCEPTION("")
	MeshUsage meshUsage=MESH_UNKNOWN;
	Mesh::sPtr mesh;
	Anims* animation=new Anims;
	DataStream ds(path);
	Mesh::SubMeshPtr subMeshs=boost::make_shared<Mesh::SubMesh>();
	Chunk* mainChunk=ds.GetMainChunk();
	if(mainChunk->GetID()!="mesh")
		EXCEPTION("")
	if(!mainChunk->HasSubChunk())
		EXCEPTION("")
	for(Chunk::ChunkIterator iter=mainChunk->GetSubChunkBegin();iter!=mainChunk->GetSubChunkEnd();iter++)
	{
		const char* data=(*iter)->GetData();
		if((*iter)->GetID()=="submesh")
		{
			MeshStr* tmpMesh=new MeshStr;
			tmpMesh->indexs=new Indexs;
			tmpMesh->texs=new Texs;
			tmpMesh->vertices=new Vertices;
			tmpMesh->weights=new Weights;
			tmpMesh->verts=new Verts;
			for(Chunk::ChunkIterator iiter=(*iter)->GetSubChunkBegin();iiter!=(*iter)->GetSubChunkEnd();iiter++)
			{	
				const char* subdata=(*iiter)->GetData();
				if((*iiter)->GetID()=="indexs")
				{
					for(int i=0;i<((*iiter)->GetSize()/sizeof(int));i++)
					{
						int tmp=0;
						memcpy(&tmp,subdata,sizeof(int));
						subdata+=sizeof(int);
						tmpMesh->indexs->push_back(tmp);
					}
				}
				else if((*iiter)->GetID()=="vertices")
				{
					for(int i=0;i<((*iiter)->GetSize()/(sizeof(float)*3));i++)
					{
						float x=0,y=0,z=0;
						memcpy(&x,subdata,sizeof(float));
						subdata+=sizeof(float);
						memcpy(&y,subdata,sizeof(float));
						subdata+=sizeof(float);
						memcpy(&z,subdata,sizeof(float));
						subdata+=sizeof(float);
						tmpMesh->vertices->push_back(XMFLOAT3(x,y,z));
					}
				}
				else if((*iiter)->GetID()=="texs")
				{
					for(int i=0;i<((*iiter)->GetSize()/(sizeof(float)*2));i++)
					{
						float tx=0,ty=0;
						memcpy(&tx,subdata,sizeof(float));
						subdata+=sizeof(float);
						memcpy(&ty,subdata,sizeof(float));
						subdata+=sizeof(float);
						tmpMesh->texs->push_back(XMFLOAT2(tx,ty));
					}
				}
				else if((*iiter)->GetID()=="texture")
				{
					string textureName(subdata);
					if(!m_resourceManager->IsLoaded(Resource::TEXTURE,textureName))
					{
						string texturePath;
						SendMessage(MSG_GET_PATH,AuxGroupArgus(textureName,&texturePath));
						SendMessage(MSG_LOAD_TEXTURE,AuxGroupArgus(textureName,texturePath));	
					}
					tmpMesh->texture=boost::shared_dynamic_cast<Texture>(m_resourceManager->GetResource(Resource::TEXTURE,textureName));
				}
				else if((*iiter)->GetID()=="verts")
				{
					for(int i=0;i<(*iiter)->GetSize()/sizeof(Vert);i++)
					{
						Vert* tmpVert=new Vert;
						memcpy(&tmpVert->start,subdata,sizeof(unsigned int));
						subdata+=sizeof(unsigned int);
						memcpy(&tmpVert->count,subdata,sizeof(unsigned int));
						subdata+=sizeof(unsigned int);
						tmpMesh->verts->push_back(tmpVert);
					}
				}
				else if((*iiter)->GetID()=="weights")
				{
					for(Chunk::ChunkIterator witer=(*iiter)->GetSubChunkBegin();witer!=(*iiter)->GetSubChunkEnd();witer++)
					{
						Weight* tmpWeight=new Weight;
						memcpy(tmpWeight,(*witer)->GetData(),sizeof(Weight));
						tmpMesh->weights->push_back(tmpWeight);
					}
				}
				else
				{
					EXCEPTION("")
				}
			}
			subMeshs->push_back(tmpMesh);
		}
		else if((*iter)->GetID()=="usage")
		{
			string usage(data);
			if(usage=="static")
			{
				meshUsage=MESH_STATIC;
			}
			else if(usage=="animation")
			{
				meshUsage=MESH_ANIM;
			}
			else
			{
				EXCEPTION("")
			}
		}
		else if((*iter)->GetID()=="anim")
		{
			AnimStr* tmpAnim=new AnimStr;
			for(Chunk::ChunkIterator aiter=(*iter)->GetSubChunkBegin();aiter!=(*iter)->GetSubChunkEnd();aiter++)
			{
				if((*aiter)->GetID()=="animName")
					tmpAnim->animName=(*aiter)->GetData();
				if((*aiter)->GetID()=="frameRate")
					memcpy(&tmpAnim->frameRate,(*aiter)->GetData(),sizeof(int));
				if((*aiter)->GetID()=="frames")
				{
					tmpAnim->keyFrames=new KeyFrame;
					for(Chunk::ChunkIterator fiter=(*aiter)->GetSubChunkBegin();fiter!=(*aiter)->GetSubChunkEnd();fiter++)
					{
						Bones* tmpBones=new Bones;
						for(Chunk::ChunkIterator biter=(*fiter)->GetSubChunkBegin();biter!=(*fiter)->GetSubChunkEnd();biter++)
						{
							Bone* tmpBone=new Bone;
							memcpy(tmpBone,(*biter)->GetData(),sizeof(Bone));
							tmpBones->push_back(tmpBone);
						}
						tmpAnim->keyFrames->push_back(tmpBones);
					}
				}
			}
			animation->push_back(tmpAnim);
		}
		else
		{
			EXCEPTION("")
		}

	}
	if(meshUsage==MESH_UNKNOWN)
		EXCEPTION("")
	switch(meshUsage)
	{
	case MESH_STATIC:
		mesh=boost::make_shared<Mesh>(ds.GetChunkName(),subMeshs,meshUsage);
		break;
	case MESH_ANIM:
		mesh=boost::make_shared<Mesh>(ds.GetChunkName(),subMeshs,animation,meshUsage);
		break;
	default:
		EXCEPTION("")
		break;
	}
	//SendMessage(MSG_LOAD_MESH,boost::shared_dynamic_cast<Resource>(mesh));
	m_resourceManager->AddResource(Resource::MESH,ds.GetChunkName(),boost::shared_dynamic_cast<Resource>(mesh));
	}
	catch(boost::bad_any_cast& e)
	{
		PRINT_BOOST_ERROR(e)
	}
	catch(std::exception& e)
	{
		PRINT_ERROR(e)
	}
}
